﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Autodesk.Revit.DB;

namespace YJKStairs.AddSigns
{
	internal class SignMaker
	{
		private SignMaker(Autodesk.Revit.DB.Document m_doc)
		{
			this.m_doc = m_doc;
		}

		internal static SignMaker GetSignMaker(Autodesk.Revit.DB.Document m_doc)
		{
			if (SignMaker.singleTag == null || m_doc == null || SignMaker.singleTag.m_doc != m_doc)
			{
				SignMaker.singleTag = new SignMaker(m_doc);
			}
			return SignMaker.singleTag;
		}

		internal string MakeTempFamily(PackerBase input, out string outFamilyName)
		{
			string text = string.Empty;
			int useI = input.UseI;
			outFamilyName = null;
			XYZ zero = XYZ.Zero;
			if (!File.Exists(StaticRescours.SignFamilyPath + StaticRescours.SingFamilyFileName[useI]))
			{
				throw new AddSignException(StaticRescours.Str_ErroParamFind);
			}
			Document document = this.m_doc.Application.OpenDocumentFile(StaticRescours.SignFamilyPath + StaticRescours.SingFamilyFileName[useI]);
			FamilyManager familyManager = document.FamilyManager;
			this.updataParameter(input, useI, familyManager, document);
			bool drawArchTag;
			List<XYZ> archPoints = this.calculatePoints(useI, zero, familyManager, out drawArchTag);
			double rotation = input.ThisFamilyInstanceLocation.Rotation;
			FamilySymbol archFamilySymbol = this.getArchFamilySymbol(useI, document);
			Transaction transaction = new Transaction(document, "creatArch");
			transaction.Start();
			Autodesk.Revit.DB.View useView;
			this.drawArch(input, document, drawArchTag, archPoints, archFamilySymbol, out useView);
			transaction.Commit();
			this.addText(input, useI, zero, document, drawArchTag, archPoints, rotation, archFamilySymbol, useView);
			outFamilyName = StaticRescours.TempFamilyName + StaticRescours.GetADateTime();
			text = StaticRescours.OutPutPath + outFamilyName + StaticRescours.Str_rfaExtend;
			document.SaveAs(text, new SaveAsOptions
			{
				OverwriteExistingFile = true
			});
			return text;
		}

		private void addText(PackerBase input, int useIndex, XYZ leftDown, Autodesk.Revit.DB.Document tempFamilyDoc, bool drawArchTag, List<XYZ> archPoints, double roateValue, FamilySymbol tempFamilySymbol, Autodesk.Revit.DB.View useView)
		{
			double num = 0.0;
			if (input.ArchCondition != ArchConditonEnum.NONE && drawArchTag && tempFamilySymbol != null)
			{
				Transaction transaction = new Transaction(tempFamilyDoc, "creatText");
				transaction.Start();
				AnnotationSymbolType annotationSymbolType = this.getAnnotationSymbolType(useIndex, tempFamilyDoc, input.ArchCondition);
				if (annotationSymbolType != null)
				{
					FamilyInstance familyInstance = tempFamilyDoc.FamilyCreate.NewFamilyInstance(archPoints[0], annotationSymbolType, useView);
					if (0.0 != roateValue)
					{
						num = Math.PI*2 - roateValue;
					}
					ElementTransformUtils.RotateElement(tempFamilyDoc, familyInstance.Id, Utility.GetZAix(archPoints[0], true), num);
					if (input.UseTransform != null)
					{
						int num2 = 1;
						roateValue = Utility.GetAXYRotateFromTransform(input.UseTransform, out num2);
						bool ifZPluse = true;
						if (num2 != 1)
						{
							ifZPluse = false;
						}
						ElementTransformUtils.RotateElement(tempFamilyDoc, familyInstance.Id, Utility.GetZAix(archPoints[0], ifZPluse), -roateValue);
					}
				}
				transaction.Commit();
			}
		}

		private void drawArch(PackerBase input, Autodesk.Revit.DB.Document tempFamilyDoc, bool drawArchTag, List<XYZ> archPoints, FamilySymbol tempFamilySymbol, out Autodesk.Revit.DB.View useView)
		{
			useView = null;
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(tempFamilyDoc);
			ElementClassFilter elementClassFilter = new ElementClassFilter(typeof(Autodesk.Revit.DB.View));
			if (0 < filteredElementCollector.WherePasses(elementClassFilter).ToElements().Count)
			{
				useView = (filteredElementCollector.WherePasses(elementClassFilter).ToElements()[0] as View);
			}
			if (input.ArchCondition != ArchConditonEnum.NONE && drawArchTag && tempFamilySymbol != null && useView != null)
			{
				switch (input.ArchCondition)
				{
				case ArchConditonEnum.UP:
				{
					XYZ xyz = new XYZ(archPoints[1].X, archPoints[1].Y - Utility.MMToFeet(StaticRescours.ArchLength, true), archPoints[1].Z);
					Line line = Line.CreateBound(archPoints[2], xyz);
					tempFamilyDoc.FamilyCreate.NewDetailCurve(useView, line);
					tempFamilyDoc.FamilyCreate.NewFamilyInstance(xyz, tempFamilySymbol, useView);
					return;
				}
				case ArchConditonEnum.DOWN:
				{
					XYZ xyz = new XYZ(archPoints[2].X, archPoints[2].Y + Utility.MMToFeet(StaticRescours.ArchLength, true), archPoints[2].Z);
					Line line = Line.CreateBound(archPoints[1], xyz);
					tempFamilyDoc.FamilyCreate.NewDetailCurve(useView, line);
					FamilyInstance familyInstance = tempFamilyDoc.FamilyCreate.NewFamilyInstance(xyz, tempFamilySymbol, useView);
					ElementTransformUtils.RotateElement(tempFamilyDoc, familyInstance.Id, Utility.GetZAix(xyz, true), Math.PI);
					break;
				}
				case ArchConditonEnum.NONE:
					break;
				default:
					return;
				}
			}
		}

		private FamilySymbol getArchFamilySymbol(int useIndex, Autodesk.Revit.DB.Document tempFamilyDoc)
		{
			FamilySymbol result = null;
			if (!tempFamilyDoc.IsFamilyDocument)
			{
				return result;
			}
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(tempFamilyDoc);
			ElementClassFilter elementClassFilter = new ElementClassFilter(typeof(FamilySymbol));
			foreach (Element element in filteredElementCollector.WherePasses(elementClassFilter).ToElements())
			{
				if (element.Name.Equals(StaticRescours.FamilySymbolNameOfArch[useIndex]))
				{
					result = (element as FamilySymbol);
					break;
				}
			}
			return result;
		}

		private AnnotationSymbolType getAnnotationSymbolType(int useIndex, Autodesk.Revit.DB.Document tempFamilyDoc, ArchConditonEnum archCondition)
		{
			AnnotationSymbolType result = null;
			if (!tempFamilyDoc.IsFamilyDocument)
			{
				return result;
			}
			string value = null;
			switch (archCondition)
			{
			case ArchConditonEnum.UP:
				value = StaticRescours.StrUpUseInParam[useIndex];
				break;
			case ArchConditonEnum.DOWN:
				value = StaticRescours.StrDownUseInParam[useIndex];
				break;
			}
			if (string.IsNullOrEmpty(value) || string.IsNullOrWhiteSpace(value))
			{
				return result;
			}
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(tempFamilyDoc);
			ElementClassFilter elementClassFilter = new ElementClassFilter(typeof(FamilySymbol));
			foreach (Element element in filteredElementCollector.WherePasses(elementClassFilter).ToElements())
			{
				if (element.Name.Equals(value))
				{
					result = (element as AnnotationSymbolType);
					break;
				}
			}
			return result;
		}

		private List<XYZ> calculatePoints(int useIndex, XYZ leftDown, FamilyManager tempFamilyManger, out bool drawArchTag)
		{
			FamilyParameter inputParameter = tempFamilyManger.get_Parameter(StaticRescours.LengthParamNameOfSign[useIndex]);
			FamilyParameter inputParameter2 = tempFamilyManger.get_Parameter(StaticRescours.WidthParamNameOfSign[useIndex]);
			double familyParameterDoubleValue = this.getFamilyParameterDoubleValue(tempFamilyManger, inputParameter);
			double familyParameterDoubleValue2 = this.getFamilyParameterDoubleValue(tempFamilyManger, inputParameter2);
			XYZ xyz = new XYZ(leftDown.X + familyParameterDoubleValue2, leftDown.Y, leftDown.Z);
			XYZ pointOne = new XYZ(leftDown.X, leftDown.Y + familyParameterDoubleValue, leftDown.Z);
			XYZ pointTwo = new XYZ(xyz.X, xyz.Y + familyParameterDoubleValue, leftDown.Z);
			XYZ midPoint = Utility.GetMidPoint(pointOne, pointTwo);
			XYZ midPoint2 = Utility.GetMidPoint(leftDown, xyz);
			XYZ item = new XYZ(midPoint.X, midPoint.Y - Utility.MMToFeet(StaticRescours.DistancofTextToUp_MM[useIndex], true), midPoint.Z);
			XYZ item2 = new XYZ(midPoint.X, midPoint.Y - Utility.MMToFeet(StaticRescours.DistanceOfArchToUp_MM[useIndex][0], true), midPoint.Z);
			XYZ item3 = new XYZ(midPoint2.X, midPoint2.Y + Utility.MMToFeet(StaticRescours.DistanceOfArchToUp_MM[useIndex][1], true), midPoint2.Z);
			List<XYZ> list = new List<XYZ>();
			list.Add(item);
			list.Add(item2);
			list.Add(item3);
			drawArchTag = false;
			if (Utility.MMToFeet(StaticRescours.DistanceOfArchToUp_MM[useIndex][1] + StaticRescours.ArchLength, true) < familyParameterDoubleValue)
			{
				drawArchTag = true;
			}
			return list;
		}

		private void updataParameter(PackerBase input, int useIndex, FamilyManager tempFamilyManger, Autodesk.Revit.DB.Document inputFamilyDoc)
		{
			Transaction transaction = new Transaction(inputFamilyDoc, "changeParam");
			transaction.Start();
			int num = 0;
			int index = 0;
			foreach (string text in StaticRescours.ParamNamesSigns[useIndex])
			{
				FamilyParameter familyParameter = tempFamilyManger.get_Parameter(text);
				if (familyParameter == null)
				{
					throw new AddSignException(StaticRescours.Str_ErroParamFind);
				}
				double num2;
				if (num <= input.DicParameters.Values.ToList<Parameter>().Count - 1)
				{
					num2 = input.DicParameters.Values.ToList<Parameter>()[num].AsDouble();
				}
				else
				{
					num2 = input.AddParamValue[index];
				}
				tempFamilyManger.Set(familyParameter, num2);
				num++;
			}
			transaction.Commit();
		}

		private XYZ findMinPoint(Autodesk.Revit.DB.Document inputFamilyDoc)
		{
			XYZ xyz = null;
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(inputFamilyDoc);
			ElementClassFilter elementClassFilter = new ElementClassFilter(typeof(DetailCurve));
			foreach (Element element in filteredElementCollector.WherePasses(elementClassFilter).ToElements().ToList<Element>())
			{
				Curve curve = ((element as DetailCurve).Location as LocationCurve).Curve;
				for (int i = 0; i <= 1; i++)
				{
					if (xyz == null)
					{
						xyz = curve.GetEndPoint(i);
					}
					else if (curve.GetEndPoint(i).Y <= xyz.Y)
					{
						if (curve.GetEndPoint(i).Y < xyz.Y)
						{
							xyz = curve.GetEndPoint(i);
						}
						else if (curve.GetEndPoint(i).X < xyz.X)
						{
							xyz = curve.GetEndPoint(i);
						}
					}
				}
			}
			return xyz;
		}

		private double getFamilyParameterDoubleValue(FamilyManager inputFamilyManger, FamilyParameter inputParameter)
		{
			double? num = new double?(0.0);
			foreach (object obj in inputFamilyManger.Types)
			{
				FamilyType familyType = (FamilyType)obj;
				if (familyType.HasValue(inputParameter))
				{
					num = familyType.AsDouble(inputParameter);
				}
			}
			if (num == null || num == null || 0.0 >= num.Value)
			{
				throw new AddSignException(StaticRescours.Str_ErroParamFind);
			}
			return num.Value;
		}

		private Document m_doc;

		private static SignMaker singleTag;
	}
}
